# -*- coding: utf-8 -*-
import ast
import base64
import urllib
import requests
import json

from collections import OrderedDict
from django.conf import settings
from Crypto.Hash import SHA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Signature import PKCS1_v1_5 as sign_pkcs1_v1_5
from Crypto.PublicKey import RSA

from async import async_job
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import SignError, NotPayOrderError, ProcessedPayOrderError, NotResponsePayIdError
from common.utils.ip_address import check_valid_ip_address

_LOGGER = track_logging.getLogger(__name__)

APP_CONF = {
    '2019070309595196': {
        'sys_pub_key': """
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4sb5MsfJhGfC1Mm6GCB+XGDKq
shXTWNCro5fAnAbvFWcflHpv/h2WVND2M8pB5Gmu6DwG2yVWcWAUn61ub3YeirzP
+igjw8IpJLB2yrbZDCQPjwZPw4t5oLETZjRroV+FIl7zg6ornmXi+hOq7V+v7Ptq
PKwliAtUCYnjZBl5CQIDAQAB
""",
        'gateway': 'http://61.160.6.34:34990/order.ashx?merid=2019070309595196',
        'query_gateway': 'http://61.160.6.34:34990/ordresult.ashx?merid=2019070309595196',
    },
}


def _get_pay_type(service):
    if service == 'alipay':
        return 'ZFB'
    elif service == 'wechat':
        return 'WX'
    else:
        return 'ZFB'


# 系统(通道)公钥
def _get_sys_pub_key(mch_id):
    return APP_CONF[mch_id]['sys_pub_key']


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


# 验签
def rsa_verify(sign, message, pub_key):
    key_bytes = base64.b64decode(pub_key)
    pub = RSA.importKey(key_bytes)
    cipher = SHA.new(message)
    t = sign_pkcs1_v1_5.new(pub).verify(cipher, base64.b64decode(urllib.unquote(sign)))
    if not t:
        _LOGGER.info("flogerpay sign not pass")
        raise SignError('flogerpay sign not pass')


# 加密
def rsa_encrypt(biz_content, public_key):
    key_bytes = base64.b64decode(public_key)
    _p = RSA.importKey(key_bytes)
    biz_content = biz_content.encode('utf-8')
    # 512bit key
    default_encrypt_length = 53
    len_content = len(biz_content)
    if len_content < default_encrypt_length:
        return base64.b64encode(PKCS1_v1_5.new(_p).encrypt(biz_content))
    offset = 0
    params_lst = []
    while len_content - offset > 0:
        if len_content - offset > default_encrypt_length:
            params_lst.append(PKCS1_v1_5.new(_p).encrypt(biz_content[offset:offset + default_encrypt_length]))
        else:
            params_lst.append(PKCS1_v1_5.new(_p).encrypt(biz_content[offset:]))
        offset += default_encrypt_length
    target = ''.join(params_lst)
    return urllib.quote(base64.b64encode(target))


# 创建支付订单
def create_charge(pay, pay_amount, info):
    app_id = info['app_id']
    service = info.get('service')
    parameter_dict = OrderedDict((
        ('merID', str(app_id)),
        ('ordNO', str(pay.id)),  # 订单编号
        ('payType', _get_pay_type(service)),  # 支付方式
        ('amount', '%.2f' % pay_amount),  # 交易金额元
        ('requestUri', '{}/pay/api/{}/flogerpay/{}'.format(
            settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
    ))
    json_data = json.dumps(parameter_dict, ensure_ascii=False)
    # 秘文
    rsa_data = rsa_encrypt(json_data, _get_sys_pub_key(app_id))
    # 通讯数据
    request_text = OrderedDict((
        ('data', rsa_data),
    ))
    json_data = json.dumps(parameter_dict)
    _LOGGER.info('flogerpay create data:%s' % json_data)
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_gateway(app_id), data=request_text, headers=headers, timeout=5)
    response_data = json.loads(response.text)
    _LOGGER.info('flogerpay response data:%s', response_data)
    if response_data['status'] == 0:
        url = response_data['url']
        # 签名验证（url是签名的数据）
        rsa_verify(response_data['sign'], url, _get_sys_pub_key(app_id))
        _LOGGER.info('flogerpay response url: %s', urllib.unquote(url))
        return {'charge_info': urllib.unquote(url)}
    return {'charge_info': response_data['error']}


# OK
def check_notify_sign(request, app_id):
    _LOGGER.info("flogerpay notify body: %s,%s", urllib.unquote(request.body), type(request.body))
    notify_data = dict(request.POST.items())
    data = ast.literal_eval(notify_data['data'])
    sign_text = '%s%s%s' % (str(data['amount']), str(data['ordNO']), str(data['pddOrdNo']))
    rsa_verify(data['sign'], sign_text, _get_sys_pub_key(app_id))

    _LOGGER.info("flogerpay notify data: %s, order_id is: %s", data, data['ordNO'])
    pay_id = data['ordNO']
    check_valid_ip_address(str(request.META['REMOTE_ADDR']), pay_id)
    if not pay_id:
        _LOGGER.error("flogerpay fatal error, out_trade_no not exists, data: %s", data)
        raise NotResponsePayIdError('flogerpay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise NotPayOrderError('flogerpay pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ProcessedPayOrderError('flogerpay pay %s has been processed' % pay_id)

    mch_id = pay.mch_id  # 商户编号
    trade_status = ''
    trade_no = data['ordNO']
    total_fee = float(data['amount'])  # 单位元
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee,
    }

    check_channel_order(pay_id, total_fee, app_id)
    # 只有支付成功才回调
    _LOGGER.info('flogerpay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
    order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
    # async notify
    async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    """ 查询订单 """
    pay_id = pay_order.id
    parameter_dict = OrderedDict((
        ('merID', str(app_id)),
        ('ordNO', str(pay_id)),  # 订单编号
    ))
    json_data = json.dumps(parameter_dict, ensure_ascii=False)
    # 秘文
    rsa_data = rsa_encrypt(json_data, _get_sys_pub_key(app_id))
    # 通讯数据
    request_text = OrderedDict((
        ('data', rsa_data),
    ))
    json_data = json.dumps(parameter_dict)
    _LOGGER.info('flogerpay create data:%s' % json_data)

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=request_text, headers=headers, timeout=5)
    data = json.loads(response.text)
    _LOGGER.info('flogerpay query response data: %s', data)
    if str(data['status']) != '-1':

        trade_status = str(data['status'])
        total_fee = float(data['amount'])  # 实际交易金额(元)
        trade_no = data['ordNO']

        message = '%s%s%s' % (str(data['amount']), str(trade_no), trade_status)
        rsa_verify(data['sign'], message, _get_sys_pub_key(app_id))
        extend = {
            'trade_status': trade_status,
            'trade_no': trade_no,
            'total_fee': total_fee,
        }
        check_channel_order(pay_id, total_fee, app_id)
        # 0创建失败，1创建成功，3支付成功，4支付超时，5已发货，6已收货
        if trade_status in ('3', '5', '6'):
            _LOGGER.info('flogerpay query order success, mch_id:%s pay_id:%s' % (pay_order.mch_id, trade_no))
            order_db.add_pay_success(pay_order.mch_id, pay_order.id, total_fee, trade_no, extend)
            async_job.notify_mch(pay_order.id)
        else:
            _LOGGER.info('flogerpay query order success, but not pay success, pay pay_id: %s,trade_status:%s'
                         % (trade_no, trade_status))
    else:
        _LOGGER.warn('flogerpay query error message: %s', data['error'])
